package com.xunwulian.web.manager;

import com.google.gson.Gson;
import com.xunwulian.base.constant.UserStatus;
import com.xunwulian.base.dao.CardInfoDao;
import com.xunwulian.base.dao.CardNodeDao;
import com.xunwulian.base.entity.CardInfoEntity;
import com.xunwulian.base.entity.CardNodeEntity;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class CardNodeManager {

    private static final Logger logger = LoggerFactory.getLogger(CardNodeManager.class);

    public static LinkedList<CardNodeEntity> nodeList = new LinkedList();

    private Gson gson = new Gson();

    @Autowired
    private CardInfoDao cardInfoDao;

    @Autowired
    private CardNodeDao cardNodeDao;

    private static final Integer THRESHOLD = 3;

    /**
     * 从cardInfo表初始化链表
     */
    public void addNode() {

        synchronized (nodeList) {

            nodeList = new LinkedList();

            List<CardInfoEntity> list = cardInfoDao.listAll();

            // 前一个号段的第一个Entity
            CardInfoEntity firstEntity = list.get(0);

            // 当前的entity
            CardInfoEntity entity = null;
            long activeNum = 1;

            for (int i = 1; i < list.size(); i++) {

                entity = list.get(i);

                // 号段之间差值在一定范围内，或者属于不同客户，或者激活日期不同，这几个字段不为空
                if (Long.valueOf(entity.getMsisdn()) - Long.valueOf(list.get(i - 1).getMsisdn()) > THRESHOLD
                        || !firstEntity.getUserId().equals(entity.getUserId())
                        || !firstEntity.getUserOpenDate().equals(entity.getUserOpenDate())) {

                    CardInfoEntity endEntity = list.get(i - 1);

                    CardNodeEntity node = new CardNodeEntity(firstEntity.getAppId(),
                            firstEntity.getAppName(),
                            firstEntity.getUserId(),
                            firstEntity.getUserName(),
                            firstEntity.getSubUserId(),
                            firstEntity.getSubUserName(),
                            Long.valueOf(firstEntity.getMsisdn()),
                            Long.valueOf(endEntity.getMsisdn()),
                            activeNum,
                            firstEntity.getPkg(),
                            firstEntity.getUserPkg(),
                            firstEntity.getUserPrice(),
                            firstEntity.getOpenDate(),
                            firstEntity.getUserOpenDate());

                    if (cardNodeDao.isExists(node.getCardNodeId()) == 0) {
                        logger.info("addNode:" + gson.toJson(node));
                        System.out.println("addNode:" + gson.toJson(node));

                        // 添加新的实体
                        nodeList.add(node);
                    }

                    firstEntity = entity;
                    activeNum = 0;
                }

                // 顺序重要，放在这里合适
                if (UserStatus.canBill(entity.getStatus())) {
                    // 统计状态为正常或者停机的卡数
                    activeNum++;
                }

            }

            CardNodeEntity node = new CardNodeEntity(entity.getAppId(),
                    entity.getAppName(),
                    entity.getUserId(),
                    entity.getUserName(),
                    entity.getSubUserId(),
                    entity.getSubUserName(),

                    Long.valueOf(firstEntity.getMsisdn()),
                    Long.valueOf(entity.getMsisdn()),
                    activeNum,

                    entity.getPkg(),
                    entity.getUserPkg(),
                    entity.getUserPrice(),
                    entity.getOpenDate(),
                    entity.getUserOpenDate());

            if (cardNodeDao.isExists(node.getCardNodeId()) == 0) {
                // 添加新的实体
                nodeList.add(node);
                logger.info("addNode:" + gson.toJson(node));
            }
        }

    }

    /**
     * 清理数据库
     */
    public boolean clearAll() {

        nodeList = new LinkedList();
        cardNodeDao.deleteAll();

        return true;
    }

    /**
     * 写入数据库
     */
    public boolean addNewNode() {

        addNode();

        if (nodeList.size() > 0) {
            cardNodeDao.insertBatch(nodeList);
        }

        return true;
    }

    /**
     * 从数据库加载
     */
    public void loadFromDB() {
        List<CardNodeEntity> cardNodeList = cardNodeDao.listAll();

        synchronized (nodeList) {
            for (CardNodeEntity node : cardNodeList) {
                nodeList.add(node);
            }
        }
    }

    /**
     * 插入新号段
     */
    public boolean insert(CardNodeEntity node) {

        synchronized (nodeList) {

            // node 对应号段已经存在，则返回node节点
            Iterator<CardNodeEntity> iterator = nodeList.iterator();
            while (iterator.hasNext()) {
                CardNodeEntity transNode = iterator.next();
                if (transNode.compareTo(node) < 0) {
                    // 在transNode之前加入新节点
                    nodeList.add(nodeList.indexOf(transNode), node);
                    cardNodeDao.insert(node);
                    break;

                } else if (nodeList.indexOf(transNode) == nodeList.size()) {

                    // 比最后一个节点还要大
                    nodeList.add(node);
                    cardNodeDao.insert(node);
                }
            }

            if (nodeList.contains(node)) {
                return true;
            } else {
                return false;
            }
        }

    }

    /**
     * 对号段设置用户Id
     */
    public boolean setUserId(
            long id,
            long start,
            long end,
            String userId,
            String userName,
            Date openDate,
            Date userOpenDate,
            String appId,
            Integer pkg,
            Integer userPkg,
            Double userPrice) {

        synchronized (nodeList) {

            if (nodeList.size() == 0) {
                loadFromDB();
            }

            System.out.println("start: " + start + ", end: " + end);


            CardNodeEntity node = cardNodeDao.getById(id);

            System.out.println("node.getStart(): " + node.getStart() + ", node.getEnd(): " + node.getEnd());

            /**
             *  区间相同
             *
             *           O            O
             *      N                       N
             */
            if (node.getStart() >= start
                    && node.getEnd() <= end) {

                logger.info("setUserId:" + userId);
                System.out.println("setUserId:" + userId);

                // 更新号段用户Id或者用户激活日期
                cardNodeDao.updateUserIdOrOpenDate(userId,
                        userName,
                        openDate,
                        userOpenDate,
                        node.getId(),
                        appId,
                        pkg,
                        userPkg,
                        userPrice);

                // 更新用户Id或者激活日期
                cardInfoDao.updateUserIdOrOpenDate(
                        userId,
                        userName,
                        String.valueOf(node.getStart()),
                        String.valueOf(node.getEnd()),
                        openDate,
                        userOpenDate,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);

            } else if (node.getStart() >= start
                    && node.getStart() < end
                    && node.getEnd() > end) {

                /**
                 *         O              O
                 *   N           N
                 */
//                if (shouldSplit(node, userId, userOpenDate)) {

                CardNodeEntity rightNode = new CardNodeEntity();
                ConvertUtils.register(new DateConverter(null),
                        java.util.Date.class);
                BeanUtils.copyProperties(node, rightNode);

//                rightNode.setEnd(end);

                rightNode.setStart(end + 1);
//                rightNode.setUserId(userId);
                rightNode.setActiveNum(rightNode.getEnd() - rightNode.getStart() + 1);

                nodeList.add(rightNode);


                logger.info("leftNode:" + gson.toJson(rightNode));
                System.out.println("leftNode:" + gson.toJson(rightNode));

                cardNodeDao.insert(rightNode);
//                }

                // newNode更新到数据库
//                node.setStart(end + 1);

                node.setEnd(end);
                cardNodeDao.updateRange(
                        node.getStart(),
                        node.getEnd(),
                        node.getId(),
                        openDate,
                        userOpenDate,
                        userId,
                        userName,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);


                // 更新用户Id或者激活日期
                cardInfoDao.updateUserIdOrOpenDate(userId,
                        userName,
                        String.valueOf(node.getStart()),
                        String.valueOf(end),
                        openDate,
                        userOpenDate,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);


            } else if (node.getStart() < start
                    && node.getEnd() >= start
                    && node.getEnd() < end) {

                /**
                 *         O                  O
                 *                    N              N
                 */
//                if (shouldSplit(node, userId, userOpenDate)) {

                CardNodeEntity rightNode = new CardNodeEntity();
                ConvertUtils.register(new DateConverter(null),
                        java.util.Date.class);
                BeanUtils.copyProperties(node, rightNode);

                rightNode.setStart(start);
                rightNode.setUserId(userId);

                nodeList.add(rightNode);
                logger.info("rightNode:" + gson.toJson(rightNode));
                System.out.println("rightNode:" + gson.toJson(rightNode));

                cardNodeDao.insert(rightNode);

//                }

                // newNode更新到数据库

                node.setEnd(start - 1);
                cardNodeDao.updateRange(
                        start,
                        node.getEnd(),
                        node.getId(),
                        openDate,
                        userOpenDate,
                        userId,
                        userName,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);

                // 更新用户Id或者激活日期
                cardInfoDao.updateUserIdOrOpenDate(
                        userId,
                        userName,
                        String.valueOf(start),
                        String.valueOf(node.getEnd()),
                        openDate,
                        userOpenDate,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);

            } else if (node.getStart() < start && node.getEnd() > end) {

                /**
                 *        O                       O
                 *              N          N
                 */
//                if (shouldSplit(node, userId, userOpenDate)) {

                CardNodeEntity leftNode = new CardNodeEntity();
                CardNodeEntity rightNode = new CardNodeEntity();

                ConvertUtils.register(new DateConverter(null),
                        java.util.Date.class);
                BeanUtils.copyProperties(node, leftNode);
                BeanUtils.copyProperties(node, rightNode);

                leftNode.setStart(node.getStart());
                leftNode.setEnd(start);

                rightNode.setStart(end);
                rightNode.setEnd(node.getEnd());

                node.setStart(start);
                node.setEnd(end);
                node.setUserId(userId);

                nodeList.add(rightNode);
                nodeList.add(leftNode);

                logger.info("add leftNode:" + gson.toJson(leftNode));
                System.out.println("add leftNode:" + gson.toJson(leftNode));

                logger.info("add rightNode:" + gson.toJson(rightNode));
                System.out.println("add rightNode:" + gson.toJson(rightNode));

                cardNodeDao.insert(leftNode);
                cardNodeDao.insert(rightNode);
//                }

                // 更新用户Id或者激活日期
                cardInfoDao.updateUserIdOrOpenDate(
                        userId,
                        userName,
                        String.valueOf(start),
                        String.valueOf(end),
                        openDate,
                        userOpenDate,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);

                // 更新用户Id或者激活日期
                cardInfoDao.updateUserIdOrOpenDate(
                        userId,
                        userName,
                        String.valueOf(start),
                        String.valueOf(end),
                        openDate,
                        userOpenDate,
                        appId,
                        pkg,
                        userPkg,
                        userPrice);
            }

//            union();
        }

        return true;
    }

    /**
     * 根据用户Id和激活日期判断是否需要拆分
     */
    private static boolean shouldSplit(CardNodeEntity node, String userId, Date userOpenDate) {
        if ((node.getUserId() != null && !node.getUserId().equals(userId)) || (node.getUserOpenDate() != null && !node.getUserOpenDate().equals(userOpenDate))) {

            return true;
        }

        return false;
    }


    /**
     * 合并userId相同的相邻区间
     */
    private boolean union() {

        synchronized (nodeList) {

            nodeList.sort(new Comparator<CardNodeEntity>() {
                @Override
                public int compare(CardNodeEntity o1, CardNodeEntity o2) {
                    return o1.compareTo(o2);
                }
            });

        }

        synchronized (nodeList) {

            CardNodeEntity pre = nodeList.getFirst();
            for (CardNodeEntity node : nodeList) {

                /**
                 *       O            O
                 *                    N             N
                 *
                 */
                if (node.getStart() == pre.getEnd() &&
                        node.getUserId().equals(pre.getUserId())) {

                    logger.info("remove " + gson.toJson(node));

                    pre.setEnd(node.getEnd());
                    nodeList.remove(node);

                    // 更新到数据库
                    cardNodeDao.updateRange(
                            pre.getStart(),
                            pre.getEnd(),
                            pre.getId(),
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null);
                    cardNodeDao.delete(node.getId());
                }
            }
        }

        return true;
    }

}
